import { read, save, clearMulti } from '@/storage'
import { login, refresh } from './user.api'
import { ACCESS_TOKEN } from '@/constants/user'

function decodeToken (token) {
  let base64Url = token.split('.')[1];
  let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
  let decodedInfo = JSON.parse(window.atob(base64));
  return {
    userid: decodedInfo.userid,
    username: decodedInfo.username,
    email: decodedInfo.email,
    nickName: decodedInfo.nickName,
    avatar: decodedInfo.avatar,
    expire: decodedInfo.expire
  }
}

const state = {
  // info
  base: {
    userid: '',
    username: '',
    email: '',
    nickName: '',
    avatar: '',
    expire: null,
  },
  access_token: '',
}

const mutations = {
  // set user info
  SET_USER_INFO (state, userInfo) {
    return state.base = {
      ...userInfo
    }
  },
  // set user token
  SET_USER_TOKEN (state, token) {
    state.access_token = token
  },
  // after logout
  LOGOUT (state) {
    // info
    state.base.userid = ''
    state.base.username = ''
    state.base.email = ''
    state.base.nickName = ''
    state.base.avatar = ''
    state.base.expire = null
    state.access_token = ''
  }
}

const actions = {
  // init user info
  initUserInfo ({ commit, dispatch, state }) {
    return new Promise((resolve, reject) => {
      const accessToken = read(ACCESS_TOKEN)
      if(accessToken) {
        let userBasic = decodeToken(accessToken)
        let f = new Date(userBasic.expire)
        let n = new Date()
        let Seconds_from_T1_to_T2 = (f.getTime() - n.getTime()) / 1000;
        // token valid
        if(Seconds_from_T1_to_T2 >= 86340) {
          commit('SET_USER_INFO', userBasic)
          commit('SET_USER_TOKEN', accessToken)
          resolve()
        } 
        // token would expire, try to get a new one
        else if(Seconds_from_T1_to_T2 > 0 && Seconds_from_T1_to_T2 < 86340) {
          refresh({ token: accessToken })
          .then(res => {
            let userBasic = decodeToken(res)
            commit('SET_USER_INFO', userBasic)
            commit('SET_USER_TOKEN', res)
            save(ACCESS_TOKEN, res)
            resolve()
          }).catch(err => {
            // clearMulti([ACCESS_TOKEN])
            reject('refresh failed')
          })
        } 
        // token expire
        else {
          reject('auth expired')
        }
      } else {
        reject('No token are found')
      }
    })
  },
  // login action
  login ({ commit, dispatch }, payload) {
    return new Promise((resolve, reject) => {
      login(payload.username, payload.password)
        .then(res => {
          let userBasic = decodeToken(res)
          commit('SET_USER_INFO', userBasic)
          commit('SET_USER_TOKEN', res)
          save(ACCESS_TOKEN, res)
          resolve()
        }).catch(err => {
          reject(err)
        })
    })
  },
}

const getters = {
  userId (state) {
    return state.id
  },
  userInfo (state) {
    return {
      id: state.id,
      username: state.username,
      nickName: state.nickName,
      email: state.email,
      userPhoto: state.userPhoto,
      mobilePin: state.mobilePin
    }
  },
  accessToken (state) {
    return state.access_token
  },
  username (state) {
    return state.username
  }
}

export default {
  state,
  mutations,
  actions,
  getters
}
